import tenpay from 'tenpay';
import { pick, sum } from 'lodash';
import BaseController from '../../core/baseController';
import { getOrderId, getCurrentStimp } from '../../utils/index';
import { ORDER_STATUS_KEYS, ORDER_TYPE, SHOP_TYPE } from '../../common/constants';

export default class OrderController extends BaseController {
  constructor(ctx) {
    super(ctx)
    this.service = ctx.service.wx.order;
    this.modelPrefix = 'xxm.order';
  }

  async list() {
    const { query } = this.ctx.validateReq('order.list');
    const { page, pageSize, ...where } = query;

    const list = await this.ctx.service.order.list(page, pageSize, where);
    this.ctx.success({
      data: list,
    });
  }

  // 微信订单支付
  async pay() {
    const { body } = this.ctx.validateReq(
      `${this.modelPrefix}.pay`,
    );

    const { user_id, people_number, table_number, order_type, address_id, note } = body;
    const { list: carList } = await this.ctx.service.wx.cart.list({ user_id });

    if (carList.length === 0) {
      this.ctx.failure({
        msg: '请重新选择商品'
      });
      return;
    }

    const order_id = getOrderId();
    const stemp = getCurrentStimp();

    const orderGoods = carList.map((it: any) => {
      const {
        goods_id, number, Good: {
          price, main_pic, name, market_price, brief
        }
      } = it;
      return {
        order_id,
        goods_id,
        price,
        main_pic,
        number,
        brief,
        market_price,
        goods_name: name,
        create_at: stemp,
        update_at: stemp
      };
    });
    const all_price = carList.filter(t => t.Good).reduce((p, n) => {
      return p + n.Good.price * n.number
    }, 0);

    // 其他价格
    let other_price = 0;
    let table_cost = 0;
    let pack_cost = 0;

    const shop = await this.ctx.model.Shop.findOne({
      where: { uuid: this.ctx.headers.shopuuid }
    });
    const { tableware, pack, type } = shop;

    const [CATERING, OTHER] = SHOP_TYPE;
    const [INSTORE, TAKEOUT, PICKUP] = ORDER_TYPE;

    // 餐饮
    if (type === CATERING) {
      // 堂食(餐具费)
      if (order_type === INSTORE) {
        table_cost = tableware * people_number;
        other_price += table_cost;
      }
      // 外卖(打包费)
      if (order_type === TAKEOUT || order_type === PICKUP) {
        pack_cost = pack * sum(orderGoods.map(it => it.number || 1));
        other_price += pack_cost;
      }
    }

    const order = {
      note,
      order_id,
      user_id,
      create_time: stemp,
      all_price: all_price + other_price,
      people_number,
      table_number,
      order_type, // 默认堂食订单
      table_cost,
      pack_cost,
      status: ORDER_STATUS_KEYS.WAIT_PAY,
      create_at: stemp,
      update_at: stemp,
    };
    // 餐饮 -> 取餐号
    if (type === CATERING) {
      const currDay = new Date().toLocaleDateString().split('/').join('');
      const keyDay = `meal_${currDay}`;
      const currNumber = this.ctx.service.set.cache.get(keyDay);
      let meal_number = 1;
      if (currNumber) {
        meal_number = currNumber + 1;
      }
      this.ctx.service.cache.set(keyDay, meal_number, 3600 * 48 * 1000) //缓存2天
      Object.assign(order, { meal_number });
    }

    // 商铺类型 (餐饮 + 外卖订单  ||  其他 + 外送) => 处理地址信息
    if (((type === CATERING && order_type === TAKEOUT) || type === OTHER) && address_id) {
      const address = await this.ctx.service.wx.address.model.findOne({
        where: { id: address_id }
      });

      const addressInfo = Object.assign(
        pick(
          address,
          ['name', 'mobile', 'address_name', 'address_detail', 'address_description']
        ),
        {
          order_id,
          create_at: stemp,
          update_at: stemp,
        });
      await this.ctx.sassmodel.OrderAddress.create(addressInfo);
    }

    await this.ctx.sassmodel.OrderGoods.bulkCreate(orderGoods);

    // 插入订单表
    await this.service.create(order);

    // 清空购物车
    await this.ctx.service.wx.cart.clear(user_id);

    // 微信统一下单
    const { payInfo: { domain, notify_url } } = this.ctx.app.config;
    const { partner_key, mchid, appid } = await this.ctx.service.shop.merchant.model.findOne({
      where: { id: this.ctx._shop.id }
    });
    const payConfig = {
      appid: appid,
      mchid: mchid,
      partnerKey: partner_key, // partnerKey
    };
    const PAYAPI = new tenpay(payConfig);
    const result = await PAYAPI.unifiedOrder({
      out_trade_no: order_id,
      body: orderGoods.map(it => it.goods_name).join('-'),
      total_fee: all_price + other_price,
      openid: user_id,
      notify_url: domain + notify_url
    });

    this.ctx.success({
      data: result,
    });
  }


  // 付款
  async orderPay() {
    const { body: { order_id, user_id } } = this.ctx.validateReq(`${this.modelPrefix}.payById`,);
    const order = await this.ctx.model.Order.findOne({
      where: {
        order_id,
        user_id
      },
      include: [
        {
          model: this.ctx.model.OrderGoods,
        }
      ],
    });
    const { all_price } = order;

    const { payInfo: { domain, notify_url } } = this.ctx.app.config;

    const { partner_key, mchid, appid } = await this.ctx.service.shop.merchant.model.findOne({
      where: { id: this.ctx._shop.id }
    });
    const payConfig = {
      appid: appid,
      mchid: mchid,
      partnerKey: partner_key, // partnerKey
    };
    const PAYAPI = new tenpay(payConfig);

    try {
      const result = await PAYAPI.unifiedOrder({
        out_trade_no: order_id,
        body: order.order_goods.map(it => it.goods_name).join('-'),
        total_fee: all_price,
        openid: user_id,
        notify_url: domain + notify_url
      });
      this.ctx.success({
        data: result,
      });
    } catch (e) {
      // await this.ctx.model.Order.update({ status: ORDER_STATUS_KEYS.PAY }, { where: { user_id, order_id } });
      this.ctx.failure({
        msg: '该订单已经支付'
      });
    }
  }

  async detail() {
    const { params: { id } } = this.ctx.validateReq(`${this.modelPrefix}.detail`,);
    const data = await this.ctx.service.order.detail(id);
    this.ctx.success({
      data,
    });
  }

  // 订单数量
  async number() {
    const { body } = this.ctx.validateReq(
      `${this.modelPrefix}.number`,
    );

    const { user_id } = body;
    const fetch = (status: string) => this.service.model.count({
      where: { user_id, status }
    });
    const statusArray = ['WAIT_PAY', 'PAY'];
    const all = statusArray.map(status => fetch(status));
    const listNumber = await Promise.all(all);

    this.ctx.success({ data: listNumber });
  }



}